package fun.symtable;

import java.util.ArrayList;
import java.util.Collections;

import fun.parser.ast.node.base.Expression;

public class DefaultSymbolTable extends AbstractSymbolTable {
    ArrayList<VariableEntry> variables = null;
    ArrayList<FunctionEntry> functions = null;

    public DefaultSymbolTable(String name) {
	super(name);
	this.variables = new ArrayList<VariableEntry>();
	this.functions = new ArrayList<FunctionEntry>();
    }

    public VariableIterator variables() {
	return new VariableIterator(this, variables.iterator());
    }

    public FunctionIterator functions() {
	return new FunctionIterator(this, functions.iterator());
    }

    public VariableEntry getVariable(String name) {
	// first search in this, if not found search in parent,etc.
	VariableEntry key = new VariableEntry(name);
	int result = Collections.binarySearch(variables, key);
	if (result >= 0)
	    return variables.get(result);
	// search in parent
	SymbolTable table = this.getParent();
	while (true) {
	    if (null == table)
		return null;
	    VariableEntry var = table.getVariable(name);
	    if (null != var)
		return var;
	    else
		table = table.getParent();
	}
    }

    public VariableEntry setVariable(String name, double value) {
	VariableEntry key = new VariableEntry(name, value);
	int result = Collections.binarySearch(variables, key);
	if (result >= 0) {
	    // found
	    variables.get(result).setValue(value);
	} else {
	    // not found, insert entry
	    this.variables.add(-result - 1, key);
	}
	return key;
    }

    public FunctionEntry getFunction(String name, int argn) {
	FunctionEntry key = new FunctionEntry(name, new String[argn], null);
	int result = Collections.binarySearch(functions, key);
	if (result >= 0)
	    return functions.get(result);
	// ==============================
	SymbolTable table = this.getParent();
	while (true) {
	    if (null == table)
		return null;
	    FunctionEntry method = table.getFunction(name, argn);
	    if (null != method)
		return method;
	    else
		table = table.getParent();
	}
    }

    public FunctionEntry setFunction(String name, String[] parameters, Expression expr) {
	FunctionEntry key = new FunctionEntry(name, parameters, expr);
	int result = Collections.binarySearch(functions, key);
	if (result >= 0) {
	    // found
	    FunctionEntry method = functions.get(result);
	    method.setParameters(parameters);
	    method.setExpression(expr);
	} else {
	    // not found, insert entry
	    this.functions.add(-result - 1, key);
	}
	return key;
    }
}
